Skip to content

feat: add runtime read-only control-plane commands#1797

Merged
aidandaly24 merged 9 commits into
refactorfrom
feat/runtime-read-only-cli
Jul 21, 2026
Merged

feat: add runtime read-only control-plane commands#1797
aidandaly24 merged 9 commits into
refactorfrom
feat/runtime-read-only-cli

Conversation

@aidandaly24

@aidandaly24 aidandaly24 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Description

Adds project-free, command-line access to inspect AgentCore Runtimes:

  • runtime get and runtime list
  • runtime version get and runtime version list
  • runtime endpoint get and runtime endpoint list

The commands follow the Harness handler/Core structure, use the existing JSON output path, and expose one-page pagination through --max-results and --next-token. Endpoint lookup uses --qualifier, mapped to the control-plane endpointName.

Runtime appears in the root TUI command menu, and bare Runtime groups print help until their TUI routes are implemented. Runtime TUI workflows, invocation, mutations, project or deployment resolution, tags and policies, agent-card operations, logs, and traces are outside this change.

Related Issue

N/A

Documentation PR

N/A. README command examples are included in this PR.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other (please describe):

Testing

Verified from current HEAD 73434193:

  • bun test --coverage --coverage-reporter=lcov (254 passed, 0 failed)
  • bun test --coverage (254 passed, 0 failed; 93.64% functions, 96.11% lines; Runtime Core and handlers 100%)
  • bun test src/handlers/runtime src/core (30 passed, 0 failed)
  • bun run lint:check
  • Changed-surface prettier --check
  • bun run typecheck
  • bun run build
  • bun run compile (all six targets)

Additional verification from Runtime-handler-equivalent commit 22634e54:

  • bun run format:check
  • bun audit
  • bun pm pack
  • Built help smokes for all nine Runtime command and group routes
  • Built CLI rejection smokes for the excluded runtime logs and runtime traces groups
  • All six live read commands and a continuation-token request in us-west-2

The committed Runtime fixtures were recorded with AWS_PROFILE=e2e-test from shared E2E account 685197708687. The dedicated Runtime agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx is retained with versions 1 and 2 plus DEFAULT and runtimeReadOnlyFixture endpoints for repeatable team recording. The fixture set contains no deploy-account identifiers or credential material.

Live read-command verification used an existing Runtime and did not mutate it. Subsequent commits change root TUI visibility and tests/fixtures only; the Runtime handlers and Core are unchanged from that live verification.

Checklist

  • I have read the CONTRIBUTING document
  • I have added necessary tests that prove the feature works
  • I have updated the documentation accordingly
  • I have added appropriate examples to the documentation
  • My changes generate no new warnings
  • No dependent changes are required

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add CLI-only get and list commands for runtimes, runtime versions, and runtime endpoints with Harness-style pagination, output, injected Core clients, fixtures, and command coverage.
@github-actions github-actions Bot added agentcore-harness-reviewing AgentCore Harness review in progress and removed agentcore-harness-reviewing AgentCore Harness review in progress labels Jul 20, 2026
@codecov-commenter

codecov-commenter commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.62092% with 44 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.25%. Comparing base (d4c31b1) to head (68afc22).

Files with missing lines Patch % Lines
src/testing/TestCoreClient.tsx 21.42% 44 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           refactor    #1797      +/-   ##
============================================
- Coverage     93.61%   93.25%   -0.37%     
============================================
  Files           117      128      +11     
  Lines          6708     7013     +305     
============================================
+ Hits           6280     6540     +260     
- Misses          428      473      +45     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aidandaly24 aidandaly24 changed the title feat(runtime): add read-only control-plane commands feat: add runtime read-only control-plane commands Jul 20, 2026

@AlexanderRichey AlexanderRichey left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on this. I think we should make two changes before merging. First, I think runtime should show in the RouterScreen, even though the TUI isn't there yet. I don't think it's worth it to carve out a special case for runtime when, in the next CR, we'll have to reverse it. Second, I think we should streamline the tests to be more consistent. We now have run(), which manually sets up mocks, and runFixture(), which returns golden file mocks. Let's only use the golden file testing pattern, if possible. So run() should become what runFixture() is and we'll just have to generate fixtures for the couple missing cases. You might have to just create a bunch of runtimes, versions, and endpoints to make this work easily when running the tests in record mode.

Comment thread src/components/RouterScreen.tsx Outdated
() => command.commands.map((c) => ({ name: c.name(), description: c.description() })),
() =>
command.commands
.filter((command) => command.name() !== "runtime")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that we haven't built the TUI for Runtime yet, but still I don't think it's worth introducing this edge case. After we build the TUI in the next CR, the original code will work as intended. Even now, I think what would happen is that the help screen would be shown, which is also fine for now.


export function createRuntimeVersionHandler(core: Core, io: AppIO): Router {
return new Router("version", "inspect AgentCore Runtime versions")
.default(createHelpDefault(io))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense for now, but it will be replaced by withTui().

Comment thread src/components/RouterScreen.test.tsx Outdated
const frame = r.lastFrame()!;
expect(frame).toContain("harness");
expect(frame).toContain("manage agentcore harnesses");
expect(frame).not.toContain("runtime");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want the main screen to show runtime.

describe("runtime control reads", () => {
test("gets a Runtime and renders the complete response", async () => {
const result = await run(["runtime", "get", "--id", "runtime-1"]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why we're not doing golden file testing for some of these cases? I think that would be both simpler and more robust.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test now uses matchGolden()

Comment thread src/core/runtime.tsx
.send(new ListAgentRuntimesCommand({ nextToken, maxResults }));
}

async listRuntimeVersions(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this follows the existing pattern, but what do think of avoiding positional arguments for functions with many arguments? I've found that using input objects makes it easier to handle optional args, and easier to read at the callsite.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree an input object would make this method easier to read in isolation, particularly with the optional pagination fields. I kept the positional signature intentionally because these Runtime methods directly mirror the existing Harness Core interface. Changing only Runtime would leave two different conventions for otherwise parallel APIs. I would prefer to keep them consistent in this PR and, if we decide input objects are the better convention, refactor both Core clients together.

flag("qualifier", "the endpoint name (qualifier)", z.string().optional()),
],
handle: async (ctx, flags) => {
if (!flags.id) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember this being brought up, but I can't remember. Why exactly can't we make these fields required in the schema to have zod validate this for us?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, I think we could make them required today for Runtime because there is no TUI yet (will be the next PR). The reason not to is how the router supports future TUI commands.

A required schema:

z.string()

becomes a mandatory Commander option. Commander rejects a bare command before middleware or the handler runs:

agentcore runtime endpoint get

But once runtime has TUI support, that bare command must reach withTuiOnEmptyFlagsAndArgs, which opens the selector screen. So, Harnerss uses optional schemas and validates inside the headless handler. I kept the same schema and headless validation pattern as the next change will be the TUI.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks that makes sense.

Comment thread src/handlers/runtime/runtime.test.tsx Outdated
expect(JSON.parse(stdout).agentRuntimeId).toBe(FIXTURE_RUNTIME_ID);
});

test("lists two Runtime pages with Harness pagination names", async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean by harness pagination names here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant here that Runtime uses the same user-facing pagination flags as Harness, --max-results and --next-token. The test name is unclear because this is the standard pagination, so I renamed it to paginates Runtime list with --max-results and --next-token.

Comment thread src/handlers/runtime/runtime.test.tsx Outdated
expect(JSON.parse(secondPage).agentRuntimes).toHaveLength(1);
});

test("maps the endpoint qualifier for a service-valid long Runtime ID", async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is a long runtime Id?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Long” was unclear. I meant a service-generated Runtime ID exceeding the 48-character Runtime name limit. Valid IDs can exceed that limit because the service appends a generated suffix. Thanks for this call out I renamed the test and explicitly assert that the fixture ID is longer than 48 characters.

@aidandaly24

Copy link
Copy Markdown
Contributor Author

Codecov Report

❌ Patch coverage is 85.62092% with 44 lines in your changes missing coverage. Please review. ✅ Project coverage is 93.25%. Comparing base (d4c31b1) to head (68afc22).
Files with missing lines Patch % Lines
src/testing/TestCoreClient.tsx 21.42% 44 Missing ⚠️
Additional details and impacted files
...

Investigated the Codecov gap. All 44 uncovered changed lines are in the private TestRuntimeClient stub, not production Runtime code. The Runtime CLI tests intentionally use the fixture-backed real CoreClient, and no Runtime TUI tests consume this fake yet. src/core/runtime.tsx and every Runtime handler have 100% line coverage. The stub currently exists only so TestCoreClient satisfies the expanded Core interface. Adding tests that only invoke its constant-return methods would not provide meaningful behavioral coverage. It will be exercised naturally by the Runtime TUI tests in the following PR.

@aidandaly24
aidandaly24 merged commit 478ec91 into refactor Jul 21, 2026
5 checks passed
@aidandaly24
aidandaly24 deleted the feat/runtime-read-only-cli branch July 21, 2026 18:27
@aidandaly24 aidandaly24 mentioned this pull request Jul 22, 2026
16 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants